import { BusinessSignals, searchParamsSignal } from "@/apis/api_signals"
import ApiFetchers from "@/apis/api_fetchers"
import { createLogger } from "@/utils/logger"
import { generateOcrCallbackUrl, getBizId, urlToFile } from "@/utils/common"
import { PayloadFormatter } from "@/utils/format"
import { signal, computed } from "@preact/signals"
import { signalWithStorage } from "@/utils/signal_utils"
import ENV from "@/utils/env"
import { navigate } from "@/utils/navigation"
import { PATHS } from "@/constants/path"
import { ErrorFactory } from "@/utils/error"

const logger = createLogger("kycController")

// 重用現有的 source data
const sourceData = BusinessSignals.kycSourceData
const expiredAt = BusinessSignals.kycExpiredAt
const leftSeconds = BusinessSignals.kycLeftSeconds

const ocrSetupParams = signalWithStorage<Partial<Kyc.Data.OcrParams>>({}, "ocrSetupParams")

// 新增一個 signal 來追蹤 URL 參數變化
// 使用 computed 計算 OCR 回調參數
const ocrCallbackParams = BusinessSignals.kycOcrCallbackParams

const ocrData = computed(() => {
    const output = {
        ...ocrSetupParams.value,
        ...ocrCallbackParams.value,
    }
    return output
})

// 定義流程順序
const stageSequence: Kyc.Flow.Stage[] = [
    { step: "step-kyc-entry" },
    { step: "step-kyc-intro-guide" },
    { step: "step-kyc-select-id-type" },
    { step: "step-kyc-ocr-callback-result" },
    { step: "step-kyc-selfie-guide" },
    { step: "step-kyc-selfie-photo" },
    { step: "step-kyc-complete-form" },
    { step: "step-kyc-success" },
]

// 流程狀態 Signals
const stageList = signal<Kyc.Flow.Stage[]>(stageSequence)
const stageListIndexMap = computed(() => {
    return Object.fromEntries(stageList.value.map((s, i) => [s.step, i])) as {
        [key in Kyc.Flow.Step]: number
    }
})
const fixedCurrentStage = signalWithStorage<Kyc.Flow.Stage | null>(null, "fixedCurrentStage")
const currentStageIndex = signalWithStorage<number>(0, "currentStageIndex")
currentStageIndex.subscribe(() => {
    fixedCurrentStage.value = null
})
const captureImage = signalWithStorage<string | null>(null, "captureImage")
const cachedFormData = signalWithStorage<Partial<Kyc.Data.Insert>>({}, "cachedFormData")

const currentStatus = computed(() => sourceData.value.kyc?.status || "unset")

function nextStage() {
    currentStageIndex.value = Math.min(currentStageIndex.value + 1, stageSequence.length - 1)
}

function prevStage() {
    currentStageIndex.value = Math.max(currentStageIndex.value - 1, 0)
}

function resetStage() {
    currentStageIndex.value = 0
}

// Computed Signals
const currentStage = computed(() => {
    if (fixedCurrentStage.value) {
        return fixedCurrentStage.value
    }

    if (ocrData.value?.step) {
        const step = ocrData.value.step as Kyc.Flow.Step
        currentStageIndex.value = stageListIndexMap.value[step]
    }
    if (currentStatus.value === "pending") {
        currentStageIndex.value = stageList.value.findIndex(
            (s) => s.step === "step-kyc-complete-form",
        )
    }

    if (currentStatus.value === "approved") {
        currentStageIndex.value = stageList.value.findIndex((s) => s.step === "step-kyc-success")
    }

    if (currentStatus.value === "final_rejected") {
        currentStageIndex.value = stageList.value.findIndex((s) => s.step === "step-kyc-entry")
    }

    return stageList.value[currentStageIndex.value] ?? { step: "step-kyc-entry" }
})

function resetFormData() {
    cachedFormData.value = {}
}

const isFetchingKyc = signal<boolean>(true)

// API 相關方法
async function fetchKyc() {
    isFetchingKyc.value = true
    await Promise.all([ApiFetchers.getKycV2(), ApiFetchers.refGetProfile()])
    isFetchingKyc.value = false
}

async function startOcr(idType: Kyc.IdType) {
    const bizId = getBizId()
    const payload = {
        bizId,
        idType,
        step: "step-kyc-ocr-callback-result" as Kyc.Flow.Step,
    }

    const finalCallbackUrl = generateOcrCallbackUrl(payload)

    const result = await ApiFetchers.startOcrProcess({
        iframe: false,
        bizId,
        idType,
        callbackUrlSuccess: finalCallbackUrl.success.href,
        callbackUrlFail: ENV.dev_mode ? finalCallbackUrl.success.href : finalCallbackUrl.fail.href,
    })

    ocrSetupParams.value = result
    return result
}

async function checkOcrResult() {
    const data = ocrData.value
    if (!data.transaction_id || !data.bizId || !data.idType) {
        return false
    }
    const result = await ApiFetchers.checkOcrResult({
        transaction_id: data.transaction_id,
        biz_id: data.bizId,
        id_type: data.idType,
    })
    return result
}

async function submitKyc(data: Kyc.Data.Insert) {
    const _data = { ...data }

    for (const key in _data) {
        const _key = key as keyof Kyc.Data.Insert
        switch (_key) {
            case "attachments_idPhoto":
            case "attachments_face":
            case "attachments_selfieWithIDPhotoPath": {
                const isBase64 = _data[_key]?.startsWith("data:image")
                if (isBase64 && _data[_key]) {
                    const file = await urlToFile(
                        _data[_key],
                        `${_key}-${sourceData.value.kyc?.uid}`,
                    )
                    logger.debug("uploadFile file", file)
                    const result = await ApiFetchers.refUploadFile(file)
                    logger.debug("uploadFile result", result)
                    _data[_key] = result?.object_key ?? ""
                }
                break
            }
        }
    }

    switch (sourceData.peek().kyc?.status) {
        case "unset": {
            return await ApiFetchers.submitKyc(_data)
        }
        default: {
            return await ApiFetchers.updateKyc(_data)
        }
    }
}

const notApprovedWithin72Hours = computed(() => {
    if (leftSeconds.value <= 0 && currentStatus.value !== "approved") {
        return true
    }
    return false
})

const from = signalWithStorage<string | null>(null, "from")

const navigateToKyc = (fixStage?: Kyc.Flow.Stage) => {
    fixedCurrentStage.value = fixStage ?? null
    from.value = location.pathname
    resetStage()
    navigate(PATHS.KYC)
}

const doItLater = () => {
    if (from.value) {
        navigate(from.value !== PATHS.KYC ? from.value : PATHS.INDEX)
    } else {
        navigate(PATHS.INDEX)
    }
}

async function updateBasicInformation(
    data: Parameters<typeof ApiFetchers.updateBasicInformation>[0],
) {
    const success = await ApiFetchers.updateBasicInformation({
        first_name: data.first_name,
        last_name: data.last_name,
        middle_name: data.middle_name,
        birthday: data.birthday,
        gender: data.gender,
    })
    if (!success) {
        throw ErrorFactory.createUnknownError("Update basic information failed")
    }
}

// 導出所有內容
const kycController = {
    // Signals
    sourceData,
    expiredAt,
    leftSeconds,
    stageList,
    currentStageIndex,
    currentStage,
    currentStatus,
    cachedFormData,
    resetFormData,
    ocrSetupParams,
    ocrData,
    isFetchingKyc,
    ocrCallbackParams,
    captureImage,
    kycOcrStatus: BusinessSignals.kycOcrStatus,
    // Methods
    nextStage,
    prevStage,
    resetStage,
    navigateToKyc,
    fetchKyc,
    startOcr,
    checkOcrResult,
    submitKyc,
    updateBasicInformation,
    fixedCurrentStage,
    notApprovedWithin72Hours,
    doItLater,
}

export default kycController
